﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Delay;

namespace lfm.Parser
{
    internal class Artist
    {
        public static async Task<lfm.Artist> getInfo(String e)
        {
            lfm.Artist result = new lfm.Artist();

            
            // Make Method Run Asynchronously
            await Task.Run(() =>
            {
                XDocument x = XDocument.Parse(e);

                // Parse main artist details
                result = (from u in x.Descendants("artist")
                            select new lfm.Artist
                            {
                                Name = u.SafeGetElement("name").SafeGetStringValue(),
                                ImageSmall = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "small").FirstOrDefault().SafeGetUriValue(),
                                ImageMedium = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "medium").FirstOrDefault().SafeGetUriValue(),
                                ImageLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "large").FirstOrDefault().SafeGetUriValue(),
                                ImageExtraLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "extralarge").FirstOrDefault().SafeGetUriValue(),
                                ImageMega = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "mega").FirstOrDefault().SafeGetUriValue(),
                                Url = u.SafeGetElement("url").SafeGetUriValue(),
                                Listeners = u.SafeGetElement("stats").SafeGetElement("listeners").SafeGetInt64Value(),
                                Playcount = u.SafeGetElement("stats").SafeGetElement("playcount").SafeGetInt64Value(),
                                BioDate = u.Element("bio").SafeGetElement("published").SafeGetDateTimeValue(DateTime.Now),
                                BioSummary = Uri.EscapeUriString(u.SafeGetElement("bio").Element("summary").SafeGetStringValue()),
                                BioContent = Uri.EscapeUriString(u.SafeGetElement("bio").Element("content").SafeGetStringValue()),
                                Streamable = Converters.ToBool(u.SafeGetElement("streamable").SafeGetStringValue()),
                                Similar = new List<lfm.Artist>(),
                                Tags = new List<lfm.Tag>()
                            }).FirstOrDefault();

                // Parse the similar artists list
                var similar = from u in x.Element("lfm").Element("artist").Element("similar").Descendants("artist")
                              select new lfm.Artist
                              {
                                  Name = u.SafeGetElement("name").SafeGetStringValue(),
                                  ImageSmall = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "small").FirstOrDefault().SafeGetUriValue(),
                                  ImageMedium = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "medium").FirstOrDefault().SafeGetUriValue(),
                                  ImageLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "large").FirstOrDefault().SafeGetUriValue(),
                                  ImageExtraLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "extralarge").FirstOrDefault().SafeGetUriValue(),
                                  ImageMega = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "mega").FirstOrDefault().SafeGetUriValue(),
                                  Url = u.SafeGetElement("url").SafeGetUriValue()
                              };

                foreach (lfm.Artist _similar in similar) result.Similar.Add(_similar);

                
            });

            // Parse the tag list
            var tags = await Generic.getTags(e);
            foreach (var t in tags) result.Tags.Add(t);
            
            // return the full artists
            return result;
        }

        public static async Task<List<lfm.Image>> getImages(String e)
        {
            List<lfm.Image> results = new List<lfm.Image>();

            // Make Method Run Asynchronously
            await Task.Run(() =>
            {
                XDocument x = XDocument.Parse(e);

                var eresult = from u in x.Descendants("image")
                              select new lfm.Image
                              {
                                  Title = u.SafeGetElement("title").SafeGetStringValue(),
                                  URL = u.SafeGetElement("url").SafeGetUriValue(),
                                  DateAdded = u.SafeGetElement("dateadded").SafeGetDateTimeValue(DateTime.Now),
                                  Format = u.SafeGetElement("format").SafeGetStringValue(),
                                  ThumbsUp = u.SafeGetElement("votes").SafeGetElement("thumbsup").SafeGetInt32Value(),
                                  ThumbsDown = u.SafeGetElement("votes").SafeGetElement("thumbsdown").SafeGetInt32Value(),
                                  Original = new Photo
                                  {
                                      URL = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "original").FirstOrDefault().SafeGetUriValue(),
                                      Width = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "original").FirstOrDefault().SafeGetAttribute("width").SafeGetInt32Value(),
                                      Height = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "original").FirstOrDefault().SafeGetAttribute("height").SafeGetInt32Value()
                                  },
                                  Large = new Photo
                                  {
                                      URL = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "large").FirstOrDefault().SafeGetUriValue(),
                                      Width = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "large").FirstOrDefault().SafeGetAttribute("width").SafeGetInt32Value(),
                                      Height = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "large").FirstOrDefault().SafeGetAttribute("height").SafeGetInt32Value()
                                  },
                                  LargeSquare = new Photo
                                  {
                                      URL = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "largesquare").FirstOrDefault().SafeGetUriValue(),
                                      Width = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "largesquare").FirstOrDefault().SafeGetAttribute("width").SafeGetInt32Value(),
                                      Height = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "largesquare").FirstOrDefault().SafeGetAttribute("height").SafeGetInt32Value()
                                  },
                                  Medium = new Photo
                                  {
                                      URL = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "medium").FirstOrDefault().SafeGetUriValue(),
                                      Width = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "medium").FirstOrDefault().SafeGetAttribute("width").SafeGetInt32Value(),
                                      Height = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "medium").FirstOrDefault().SafeGetAttribute("height").SafeGetInt32Value()
                                  },
                                  Small = new Photo
                                  {
                                      URL = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "small").FirstOrDefault().SafeGetUriValue(),
                                      Width = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "small").FirstOrDefault().SafeGetAttribute("width").SafeGetInt32Value(),
                                      Height = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "small").FirstOrDefault().SafeGetAttribute("height").SafeGetInt32Value()
                                  },
                                  ExtraLarge = new Photo
                                  {
                                      URL = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "extralarge").FirstOrDefault().SafeGetUriValue(),
                                      Width = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "extralarge").FirstOrDefault().SafeGetAttribute("width").SafeGetInt32Value(),
                                      Height = u.Elements("sizes").Elements("size").Where(n => n.SafeGetAttribute("name").Value == "extralarge").FirstOrDefault().SafeGetAttribute("height").SafeGetInt32Value()
                                  }
                              };

                foreach (lfm.Image i in eresult)
                {
                    results.Add(i);
                }
            });

            // return the full artists
            return results;
        }

        public static async Task<List<lfm.Artist>> getSimilar(String e)
        {
            List<lfm.Artist> result = new List<lfm.Artist>();

            // Make Method Run Asynchronously
            await Task.Run(() =>
            {
                XDocument x = XDocument.Parse(e);

                // Parse the similar artists list
                var similar = from u in x.Descendants("artist")
                              select new lfm.Artist
                              {
                                  Name = u.SafeGetElement("name").SafeGetStringValue(),
                                  ImageSmall = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "small").FirstOrDefault().SafeGetUriValue(),
                                  ImageMedium = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "medium").FirstOrDefault().SafeGetUriValue(),
                                  ImageLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "large").FirstOrDefault().SafeGetUriValue(),
                                  ImageExtraLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "extralarge").FirstOrDefault().SafeGetUriValue(),
                                  ImageMega = u.Elements("image").Where(n => n.SafeGetAttribute("size").Value == "mega").FirstOrDefault().SafeGetUriValue(),
                                  Url = u.SafeGetElement("url").SafeGetUriValue(),
                                  Match = Converters.ToDouble(u.SafeGetElement("match").SafeGetStringValue()),
                                  Streamable = Converters.ToBool(u.SafeGetElement("streamable").SafeGetStringValue())
                              };

                foreach (var s in similar) result.Add(s);
            });

            // return the full artists
            return result;
        }

        public static async Task<List<lfm.Artist>> search(String e)
        {
            List<lfm.Artist> result = new List<lfm.Artist>();

            // Make Method Run Asynchronously
            await Task.Run(() =>
            {
                XDocument x = XDocument.Parse(e);

                // Parse the similar artists list
                var searchres = from u in x.Descendants("artist")
                              select new lfm.Artist
                              {
                                  Name = u.SafeGetElement("name").SafeGetStringValue(),
                                  ImageSmall = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "small").FirstOrDefault().SafeGetUriValue(),
                                  ImageMedium = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "medium").FirstOrDefault().SafeGetUriValue(),
                                  ImageLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "large").FirstOrDefault().SafeGetUriValue(),
                                  ImageExtraLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "extralarge").FirstOrDefault().SafeGetUriValue(),
                                  ImageMega = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "mega").FirstOrDefault().SafeGetUriValue(),
                                  Url = u.SafeGetElement("url").SafeGetUriValue(),
                                  Streamable = Converters.ToBool(u.SafeGetElement("streamable").SafeGetStringValue()),
                                  Listeners = u.SafeGetElement("listeners").SafeGetInt64Value()
                              };

                foreach (var s in searchres) result.Add(s);
            });

            // return the full artists
            return result;
        }

        public static async Task<List<lfm.Album>> getTopAlbums(String e)
        {
            List<lfm.Album> result = new List<lfm.Album>();

            // Make Method Run Asynchronously
            await Task.Run(() =>
            {
                XDocument x = XDocument.Parse(e);

                // Parse the similar artists list
                var albums = from u in x.Descendants("album")
                             select new lfm.Album
                             {
                                 Name = u.SafeGetElement("name").SafeGetStringValue(),
                                 Playcount = u.SafeGetElement("playcount").SafeGetInt64Value(),
                                 URL = u.SafeGetElement("url").SafeGetUriValue(),
                                 Artist = new lfm.Artist
                                 {
                                     Name = u.SafeGetElement("artist").SafeGetElement("name").SafeGetStringValue(),
                                     Url = u.SafeGetElement("artist").SafeGetElement("url").SafeGetUriValue()
                                 },
                                 ImageSmall = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "small").FirstOrDefault().SafeGetUriValue(),
                                 ImageMedium = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "medium").FirstOrDefault().SafeGetUriValue(),
                                 ImageLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "large").FirstOrDefault().SafeGetUriValue(),
                                 ImageExtraLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "extralarge").FirstOrDefault().SafeGetUriValue()
                             };

                foreach (var s in albums) result.Add(s);
            });

            // return the full artists
            return result;
        }

        public static async Task<List<lfm.Event>> getEvents(String e)
        {
            List<lfm.Event> result = new List<lfm.Event>();

            // Make Method Run Asynchronously
            await Task.Run(() =>
            {
                String r = e;
                r = r.Replace("geo:point", "point");
                r = r.Replace("geo:lat", "lat");
                r = r.Replace("geo:long", "long");

                XDocument x = XDocument.Parse(r);

                // Parse the similar artists list
                var events = from u in x.Descendants("event")
                             select new lfm.Event
                             {
                                 ID = u.SafeGetElement("id").SafeGetInt64Value(),
                                 Title = u.SafeGetElement("title").SafeGetStringValue(),
                                 StartDate = u.SafeGetElement("startdate").SafeGetDateTimeValue(DateTime.Now),
                                 EndDate = u.SafeGetElement("enddate").SafeGetDateTimeValue(DateTime.Now),
                                 Description = u.SafeGetElement("description").SafeGetStringValueEmptyable(),
                                 ImageSmall = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "small").FirstOrDefault().SafeGetUriValue(),
                                 ImageMedium = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "medium").FirstOrDefault().SafeGetUriValue(),
                                 ImageLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "large").FirstOrDefault().SafeGetUriValue(),
                                 ImageExtraLarge = u.Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "extralarge").FirstOrDefault().SafeGetUriValue(),
                                 Attendance = u.SafeGetElement("attendance").SafeGetInt64Value(),
                                 Reviews = u.SafeGetElement("reviews").SafeGetInt64Value(),
                                 Tag = u.SafeGetElement("tag").SafeGetStringValue(),
                                 URL = u.SafeGetElement("url").SafeGetUriValue(),
                                 Website = u.SafeGetElement("website").SafeGetUriValue(),
                                 Tickets = u.SafeGetElement("tickets").SafeGetUriValue(),
                                 Cancelled = Converters.ToBool(u.SafeGetElement("url").SafeGetStringValue()),
                                 Venue = new Venue
                                 {
                                     ID = u.SafeGetElement("venue").SafeGetElement("id").SafeGetInt64Value(),
                                     Name = u.SafeGetElement("venue").SafeGetElement("name").SafeGetStringValue(),
                                     City = u.SafeGetElement("venue").SafeGetElement("location").SafeGetElement("city").SafeGetStringValue(),
                                     Country = u.SafeGetElement("venue").SafeGetElement("location").SafeGetElement("country").SafeGetStringValue(),
                                     Street = u.SafeGetElement("venue").SafeGetElement("location").SafeGetElement("street").SafeGetStringValue(),
                                     PostalCode = u.SafeGetElement("venue").SafeGetElement("location").SafeGetElement("postalcode").SafeGetStringValue(),
                                     Latitude = u.SafeGetElement("venue").SafeGetElement("location").SafeGetElement("point").SafeGetElement("lat").SafeGetStringValue(),
                                     Longtitude = u.SafeGetElement("venue").SafeGetElement("location").SafeGetElement("point").SafeGetElement("long").SafeGetStringValue(),
                                     URL = u.SafeGetElement("venue").SafeGetElement("url").SafeGetUriValue(),
                                     Website = u.SafeGetElement("venue").SafeGetElement("website").SafeGetUriValue(),
                                     PhoneNumber = u.SafeGetElement("venue").SafeGetElement("phonenumber").SafeGetStringValue(),
                                     ImageSmall = u.SafeGetElement("venue").Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "small").FirstOrDefault().SafeGetUriValue(),
                                     ImageMedium = u.SafeGetElement("venue").Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "medium").FirstOrDefault().SafeGetUriValue(),
                                     ImageLarge = u.SafeGetElement("venue").Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "large").FirstOrDefault().SafeGetUriValue(),
                                     ImageExtraLarge = u.SafeGetElement("venue").Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "extralarge").FirstOrDefault().SafeGetUriValue(),
                                     ImageMega = u.SafeGetElement("venue").Elements("image").Where(n => n.SafeGetAttribute("size").SafeGetStringValue() == "mega").FirstOrDefault().SafeGetUriValue()
                                 },
                                 TempArtists = (from a in u.Element("artists").Descendants("artist") select new lfm.Artist { Name = a.SafeGetStringValue() }),
                                 Artists = new List<String>(),
                                 Headliner = u.SafeGetElement("artists").SafeGetElement("headliner").SafeGetStringValue()
                             };

                foreach (var s in events)
                {
                    // Populate the artists list
                    foreach (var a in s.TempArtists)
                    {
                        if (a != null) s.Artists.Add(a.Name);
                    }
                    result.Add(s);
                }
            });

            // return the full artists
            return result;
        }
    }
}
